<?php
/**
 * Default controller
 *
 * @author André Silva
 */
class PublicController {
	/**
	 * @var string
	 */
	protected $view;
	/**
	 * @var string
	 */
	protected $buffer;
	/**
	 * @var string
	 */
	protected $template = APPLICATION_TEMPLATE;
	/**
	 * @var boolean
	 */
	protected $hasError = false;
	/**
	 * @var array
	 */
	public $messages = array();
	/**
	 * @var array
	 */
	protected $filters = array();
	/**
	 * @var array
	 */
	protected $valitators = array();

	public function __construct() {
		$this->setView('application.views.'.Cerberus::getControllerName());
	}

	/**
	 * Execute all events for the controller
	 */
	public function execute() {
		$this->onStart();

		$this->addFilters();

		if($this->loadFilters()) {
			if (count($_POST) > 0 ) {
				$this->addValidators();
				if($this->loadValidators()) {
					$this->onRequest();
				}
			}
		}

		$this->onExecute();

		if (!empty($this->view)) {
			$this->buffer = file_get_contents($this->view);
			$this->onParse();
		}
	}

	/**
	 * Executed before filter execution
	 */
	protected function onStart() {

	}

	/**
	 * Executed when the controller receive user input
	 */
	protected function onRequest() {

	}

	/**
	 * Executed after validation
	 */
	protected function onExecute() {

	}

	/**
	 * Executed before controller exit
	 */
	public function onFinish() {

	}

	/**
	 * Parse output view
	 */
	protected function onParse() {
		$this->loadTemplate();

		while (($var = Parser::getVariable($this->buffer))) {
			$value = $var['name'];
			if (strpos($value, '.')) {
				$value = Parser::getValue($this, $value);
			} else {
				$value = $this->$value;
			}
			$this->replace($var['tag'], $value);
		}

		Parser::parseTags($this->buffer, $this);
	}


	protected function setTitle($value) {
		$this->buffer = $this->replace('<title>.*</title>', '<title>'.$value.'<title>');
	}

	protected function loadTemplate() {
		$view = Cerberus::resolvePath($this->template, true).'.tpl';

		if (!file_exists($view)) {
			throw new Exception('Template not found: ' . $this->template);
		}

		$buffer = file_get_contents($view);

		$blocks = array();
		while (($block = Parser::getTag($this->buffer, 'block'))) {
			$blocks[] = $block;
			$this->replace($block['tag'], '');
		}

		while (($holder = Parser::getTag($buffer, 'block'))) {
			// enabled="false"
			if (isset($holder['properties']['enabled']) && $holder['properties']['enabled'] == 'false') {
				$buffer = str_replace($holder['tag'], '', $buffer);
				continue;
			}

			// src="file.php"
			if (isset($holder['properties']['src'])) {
				$file = APPLICATION_ROOT.$holder['properties']['src'];
				if (!file_exists($file)) {
					throw new Exception('Template block not found: ' . $holder['properties']['src']);
				}
				$block = file_get_contents($file);
				$buffer = str_replace($holder['tag'], $block, $buffer);
				continue;
			}

			if (isset($holder['properties']['id'])) {
				$clear = true;
				if (!empty($blocks)) {
					foreach ($blocks as $block) {
						if ($block['properties']['id'] == $holder['properties']['id']) {
							$buffer = str_replace($holder['tag'], $block['content'], $buffer);
							$clear = false;
							break;
						}
					}
				}
				if ($clear) {
					$buffer = str_replace($holder['tag'], '', $buffer);
				}
				continue;
			}
			throw new Exception('Invalid template block: ' . $holder);
		}

		// Update content
		$this->buffer = $buffer;
	}

	/**
	 * Override to load validators
	 */
	protected function addValidators() {

	}

	/**
	 * Load all validators
	 * @return boolean
	 */
	protected function loadValidators() {
		if ($this->hasError) {
			return false;
		}
		while (count($this->valitators) > 0) {
			$validator = array_shift($this->valitators);
			$validator->invoke($this);
		}
		return !$this->hasError;
	}

	/**
	 * Add a validator
	 * @param IValidator $validator
	 */
	public function addValidator($validator) {
		if(!Cerberus::hasInterface($validator, 'IValidator')) {
			throw new Exception('IValidator not implemented in '.get_class($validator));
		}
		array_push($this->valitators, $validator);
	}

	/**
	 * Override to load filters
	 */
	protected function addFilters() {

	}

	/**
	 * Load all filters
	 * @return boolean
	 */
	protected function loadFilters() {
		while (count($this->filters) > 0) {
			$filter = array_shift($this->filters);
			if (!$filter->invoke($this)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Add a filter
	 * @param IFilter $filter
	 */
	public function addFilter($filter) {
		if(!Cerberus::hasInterface($filter, 'IFilter')) {
			throw new Exception('IFilter not implemented in '.get_class($filter));
		}
		array_push($this->filters, $filter);
	}

	/**
	 * Set the controller using a virtual path
	 * @param string $view
	 */
	public function setView($view) {
		$viewPath = Cerberus::resolvePath($view, true).'.tpl';
		if (file_exists($viewPath)) {
			$this->view = $viewPath;
		}
	}

	/**
	 * Add a message
	 * @param string $message
	 * @param string $type
	 */
	public function addMessage($message, $type='success') {
		$this->messages[$type][] = $message;
	}

	/**
	 * Add a error message
	 * @param string $message
	 * @param string $type
	 */
	public function addError($message, $type='error') {
		$this->hasError = true;
		$this->messages[$type][] = $message;
	}

	/**
	 * Return if the current controller have some message
	 * @return boolean
	 */
	public function hasMessage() {
		return !empty ($this->messages);
	}

	/**
	 * Return if the current controller have some error
	 * @return boolean
	 */
	public function hasError() {
		return $this->hasError;
	}

	/**
	 * Replace a strings inside controller content
	 * @param string $string
	 * @param string $replacement
	 */
	public function replace($string, $replacement) {
		$this->buffer = str_replace($string, $replacement, $this->buffer);
	}

	/**
	 * Redirect to a url
	 * @param string $url
	 */
	public function redirect($url) {
		header('location: /' . $url);
	}

	/**
	 * Get current controller content
	 * @return string
	 */
	public function getBuffer() {
		return $this->buffer;
	}
}
?>
